home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / DTS QT Utilities.Aug-95 / DTSQTUtilities.c < prev    next >
Encoding:
Text File  |  1995-07-17  |  57.5 KB  |  1,781 lines  |  [TEXT/MPCC]

  1. /*
  2.     File:        DTSUtilities.c
  3.  
  4.     Contains:    QuickTime functions.
  5.  
  6.     Written by:    DTS
  7.  
  8.     Copyright:    © 1994-1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.        <1>         12/17/94    khs        first file
  13.        
  14. */
  15.  
  16.  
  17. // INCLUDES
  18. #include "DTSQTUtilities.h"
  19.  
  20.  
  21. // MOVIE TOOLBOX FUNCTIONS
  22.  
  23. /*______________________________________________________________________
  24.     QTUIsQuickTimeInstalled - Test if QuickTime is installed.
  25.  
  26. pascal Boolean    QTUIsQuickTimeInstalled(void) 
  27.  
  28. DESCRIPTION
  29.     InitQuickTime will test if QuickTime is present. We are not interested in the QuickTime
  30.     version.
  31.  
  32. ISSUES
  33.     You could combine this function with the QTUGetQTVersion so you could also fetch the
  34.     version level of QT at the same time.
  35. */
  36.  
  37. pascal Boolean QTUIsQuickTimeInstalled(void) 
  38. {
  39.     OSErr     anErr = noErr;
  40.     long         qtVersion;
  41.  
  42.     anErr = Gestalt(gestaltQuickTime, &qtVersion); DebugAssert(anErr == noErr);
  43.     if (anErr != noErr)
  44.         return false;        // no QT present
  45.     else
  46.         return true;
  47. }
  48.  
  49.  
  50. /*______________________________________________________________________
  51.     QTUIsQuickTimeCFMInstalled - Test if the QuickTime CFM libraries are installed and in the 
  52.     right place.
  53.  
  54. pascal Boolean    QTUIsQuickTimeCFMInstalled(void) 
  55.  
  56. DESCRIPTION
  57.     QTUIsQuickTimeCFMInstalled will test if the CFM QuickTime libraries are present (QuickTime 
  58.     PowerPlug, for instance), and if the libraries are still present (this because the libraries are 
  59.     registered once when Gestalt finds then during runtime, and the end user might delete these, 
  60.     or move them to another location later)(.
  61. */
  62.  
  63. #ifdef powerc
  64. pascal Boolean QTUIsQuickTimeCFMInstalled(void) 
  65. {
  66.     OSErr     anErr = noErr;
  67.     long         qtFeatures = 0L; 
  68.  
  69. // Test if the library is registered.
  70.     anErr = Gestalt(gestaltQuickTimeFeatures, &qtFeatures); DebugAssert(anErr == noErr);
  71.     
  72.     if (!(  (anErr == noErr)  &&  (qtFeatures & (1 << gestaltPPCQuickTimeLibPresent))  )) // not true
  73.           return false;
  74.           
  75. // Test if a function is available (the library is not moved from the Extension folder),  this is the 
  76. // trick to be used concerning testing if a function is available via CFM.
  77.  
  78.     if   ( ! CompressImage )
  79.         return false;     
  80.     else 
  81.         return true;
  82. }
  83. #endif // powerc
  84.  
  85.  
  86. /*______________________________________________________________________
  87.     QTUGetQTVersion - Return the current QuickTime version number.
  88.  
  89. pascal long QTUGetQTVersion()
  90.  
  91. DESCRIPTION
  92.     QTUGetQTVersion is a simple function that will return the current QuickTime version number,
  93.     and if QuickTime is not installed it will return 0L.  The high order word defines the version number, 
  94.     for instance 0x0161 defines version 1.6.1.
  95.     
  96.     You could also directly assign a boolean value stating if a certain version is true by using this
  97.     kind of an expression:
  98.     
  99.     Boolean gHasQT2.0 = (( QTUGetQTVersion() >>  16) & 0xFFFF) >= 0x200;
  100.     
  101. EXAMPLE
  102.     if( (QTUGetQTVersion() >> 16) < 0x150 ) return; // need to work with QT 1.5 or higher.
  103. */
  104.  
  105. pascal long QTUGetQTVersion()
  106. {
  107.     long version = 0L;
  108.     
  109.     if(Gestalt(gestaltQuickTime, &version) == noErr)
  110.         return version;
  111.     else
  112.         return 0L;
  113. }
  114.  
  115.  
  116. /*______________________________________________________________________
  117.     QTUAreQuickTimeMusicInstrumentsPresent - Test if the Musical Instruments Extension is 
  118.     installed.
  119.  
  120. pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void)
  121.  
  122. DESCRIPTION
  123.     QTUAreQuickTimeMusicInstrumentsPresent tests if the QuickTime Musical Instruments
  124.     extension (actually a component) is registered. If this is not the case, then most likely
  125.     the extension was never placed into the extension folder, and the end user should be
  126.     informed about this.
  127. */
  128.  
  129. pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void)
  130. {
  131.     ComponentDescription aCD;
  132.     
  133.     aCD.componentType = 'inst';
  134.     aCD.componentSubType = 'ss  ';
  135.     aCD.componentManufacturer = 'appl';
  136.     
  137.     if(FindNextComponent((Component)0, &aCD) != NULL)
  138.         return true;
  139.     else
  140.         return false;
  141. }
  142.  
  143.  
  144. /*______________________________________________________________________
  145.      QTUPrerollMovie - Preroll the movie before you start the movie.
  146.  
  147. pascal OSErr QTUPrerollMovie(Movie theMovie)
  148.  
  149. theMovie                the destination movie for this operation
  150.  
  151. DESCRIPTION
  152.     QTUPrerollMovie will get the movie time,  duration and preferred rate, and Preroll the movie 
  153.     based on this information. Note that StartMovie already does a PrerollMovie so in that case this 
  154.     is not needed, this is also true of the standard controller that handles the start of movie
  155.     when the keyboard or mouse is used.
  156. */
  157.  
  158. pascal OSErr QTUPrerollMovie(Movie theMovie) 
  159. {
  160.     OSErr                anErr = noErr;
  161.     TimeValue         aTimeValue;
  162.     TimeValue            aMovieDur;
  163.     Fixed                 aPreferredRate;
  164.  
  165.     aTimeValue          = GetMovieTime(theMovie, NULL);
  166.     aMovieDur         = GetMovieDuration(theMovie);
  167.     aPreferredRate  = GetMoviePreferredRate(theMovie);
  168.  
  169.     if(aTimeValue == aMovieDur) aTimeValue = 0;
  170.  
  171.     anErr = PrerollMovie(theMovie, aTimeValue, aPreferredRate); DebugAssert(anErr == noErr);
  172.     
  173.     return anErr;
  174. }
  175.  
  176.  
  177. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock);
  178.  
  179.  
  180. /*______________________________________________________________________
  181.     QTUGetMovie - Get a Movie from a specific file.
  182.  
  183. pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID)
  184.  
  185. theFSSpec                the specific FSSpec used, if NULL the system will use a standard dialog
  186.                             box for the end user to select a file
  187. theRefNum            this is the specific file ref num we want to use later
  188. theResID                this is the specific resource ID we want to use later
  189.  
  190. DESCRIPTION
  191.     QTUGetMovie will get a movie resource out from a specified file, if the FSSpec is not provided
  192.     then the function will use a StandardGetFilePreview to select the movie.
  193. */
  194.  
  195. pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID)
  196. {
  197.     OSErr                    anErr = noErr;
  198.     SFTypeList            aTypeList = {MovieFileType, 0, 0, 0};
  199.     StandardFileReply    aReply;
  200.     Movie                    aMovie = NULL;
  201.  
  202. // If we are provided with an FSSpec then use it, otherwise do a standardgetfile dialog box and 
  203. // ask the end user to get it.
  204.     if(theFSSpec == NULL || theFSSpec->vRefNum == 0)
  205.     {    
  206.         StandardGetFilePreview( NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply);
  207.         if(! aReply.sfGood)
  208.             return NULL;
  209.         
  210.         *theFSSpec = aReply.sfFile;
  211.     }
  212.  
  213.     // We should have now a usable FSSpec, just double check this once again before continuing.
  214.     DebugAssert(theFSSpec != NULL); if(theFSSpec == NULL) return NULL;
  215.     
  216.     anErr = OpenMovieFile(theFSSpec, theRefNum, fsRdPerm); DebugAssert(anErr == noErr);
  217.     // Note we define fsRdPerm, you could use another flag if needed.
  218.  
  219.     if(anErr == noErr)
  220.     {
  221.         Str255    aMovieName;
  222.         Boolean    wasChanged;
  223.         
  224.         *theResID = 0;                    // want first movie
  225.         
  226.         anErr = NewMovieFromFile(&aMovie, *theRefNum, theResID,
  227.                                                     aMovieName, newMovieActive, &wasChanged);
  228.  
  229.         DebugAssert(anErr == noErr);
  230.  
  231.         CloseMovieFile(*theRefNum);
  232.     }
  233.     
  234.     if(anErr != noErr)
  235.         return NULL;
  236.     else
  237.         return aMovie;
  238. }
  239.  
  240.  
  241. /*______________________________________________________________________
  242.     QTUSimpleGetMovie - Get a Movie from a specific file (simpler version)
  243.  
  244. pascal OSErr QTUSimpleGetMovie(Movie *theMovie)
  245.  
  246. theMovie                will contain the selected movie when function exits.
  247.  
  248. DESCRIPTION
  249.     QTUSimpleGetMovie is a simplified version of getting a movie from a file, no need for
  250.     returning refnums, res IDs of keeping track of FSSpecs (compared with QTUGetMovie)
  251. */
  252.  
  253. pascal OSErr QTUSimpleGetMovie(Movie *theMovie)
  254. {
  255.     OSErr                     anErr = noErr;
  256.     SFTypeList            aTypeList = {MovieFileType, 0, 0, 0};
  257.     short                    resFile = 0;
  258.     short                    resID = 0;
  259.     StandardFileReply    aReply;
  260.     Str255                    movieName;
  261.     Boolean                    wasChanged;
  262.  
  263.     StandardGetFilePreview(NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply);
  264.     if(aReply.sfGood)
  265.     {
  266.         anErr = OpenMovieFile(&aReply.sfFile, &resFile, fsRdPerm); DebugAssert(anErr == noErr);
  267.         if(anErr == noErr)
  268.         {
  269.             anErr = NewMovieFromFile(theMovie, resFile, &resID, movieName, newMovieActive, &wasChanged);
  270.             DebugAssert(anErr == noErr);
  271.  
  272.             CloseMovieFile(resFile);
  273.         }
  274.     }
  275.     return anErr;
  276. }
  277.  
  278.  
  279. /*______________________________________________________________________
  280.     QTUFileFilter - Skeleton file filter to be used with various MovieToolbox standard dialog utilities.
  281.  
  282. pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock)
  283.  
  284. theParamBlock        specifies a particular ParmBlockPtr
  285.  
  286. DESCRIPTION
  287.     QTUFileFilter is a skeleton file filter to be used with various MovieToolbox standard dialog utilities
  288.     The function will return a boolean false if it encounters any errors from the Movie toolbox.
  289. */
  290.  
  291. pascal Boolean QTUFileFilter(ParmBlkPtr /*theParamBlock */)
  292. {
  293.     return false;
  294. }
  295.  
  296.  
  297. /*______________________________________________________________________
  298.       QTUSaveMovie - Save and flatten a movie resource into a  file.
  299.  
  300. pascal OSErr QTUSaveMovie(Movie theMovie)
  301.  
  302. theMovie            defines the movie to be saved into a file
  303.  
  304. DESCRIPTION
  305.     QTUSaveMovie will provide a user dialog asking for a file name, and will then save the movie
  306.     into this file. Note that this function will also automatically flatten the movie so that  it's 
  307.     self-contained, and also make it cross-platform (by adding any possible resource forks to
  308.     the end of the data fork. The default name of the movie is also NEWMOVIE.MOV, this reflects
  309.     the way movie file names should be named for cross-platform support (Windows). The default
  310.     creator type is also 'TVOD' so that MoviePlayer will be the default application that opens the
  311.     movie file. If there's an existing movie file with the same name, it will be deleted.
  312. */
  313.  
  314.  
  315. pascal OSErr QTUSaveMovie(Movie theMovie)
  316. {
  317.     OSErr                     anErr = noErr;
  318.     StandardFileReply    anSFReply;
  319.     
  320.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  321.     
  322.     StandardPutFile("\pSave Movie as:" , "\pNEWMOVIE.MOV", &anSFReply); 
  323.     if(anSFReply.sfGood)
  324.     {
  325.  
  326.         FlattenMovieData(theMovie, flattenAddMovieToDataFork, &anSFReply.sfFile, 
  327.                                         'TVOD', smSystemScript, createMovieFileDeleteCurFile );
  328.         anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  329.     }
  330.         return anErr;
  331. }
  332.  
  333.  
  334. /*______________________________________________________________________
  335.     QTUFlattenMovieFile - Flatten a movie into a specified file.
  336.  
  337. pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile)
  338.  
  339. theMovie                defines the movie to be flattened
  340. theFile                    defines the target file
  341.  
  342. DESCRIPTION
  343.     FlattenMovie file will take an existing movie, flatten it into a temp file, and then move the
  344.     contents of the temp file into the specified FSSpec. This because there are cases where we 
  345.     can't flatten a movie in place. We will use TickCount as a temp file name.    
  346.     
  347.     Note that we need to dispose the movie inside this function? Why? Well, the file is open as
  348.     long as there's a pointer to it from the movie resource. And we need to delete the original 
  349.     movie file as part of the operation of swapping the files. 
  350. */
  351.  
  352. pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile)
  353. {
  354.     OSErr         anErr = noErr;
  355.     FSSpec         tempFile;
  356.     Str255     tempFileName;
  357.     
  358.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  359.     
  360.     // Create the needed temp file.
  361.     NumToString(TickCount(), tempFileName);
  362.         anErr = FSMakeFSSpec(theFile->vRefNum, theFile->parID, tempFileName, &tempFile);
  363.     if(anErr != fnfErr) return anErr;
  364.     
  365.     // Flatten the movie.
  366.     FlattenMovie(theMovie, flattenAddMovieToDataFork, &tempFile, 'TVOD', smSystemScript, 
  367.                             createMovieFileDeleteCurFile, 0, NULL);
  368.     anErr = GetMoviesError();
  369.     if(anErr != noErr)
  370.     {
  371.         FSpDelete(&tempFile);        // remove the temp file
  372.         return anErr;
  373.     }
  374.     
  375.     DisposeMovie(theMovie);
  376.     anErr = FSpDelete(theFile);  ReturnIfError(anErr);
  377.     anErr = FSpRename(&tempFile, theFile->name); ReturnIfError(anErr);
  378.     
  379.     return anErr;
  380. }
  381.  
  382.  
  383. // TRACKS AND MEDIA
  384.  
  385. /*______________________________________________________________________
  386.     QTUMediaTypeInTrack - Check if a particular media type is present in the movie.
  387.  
  388. pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType)
  389.  
  390. theMovie                    movie to be tested about the media type
  391. theMediaType            media type we want to test about
  392.  
  393. DESCRIPTION
  394.     QTUMediaTypeInTrack could be used to scan if a possible media type is present in the movie 
  395.     (video,sound, other media types).
  396. */
  397.  
  398. pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType)
  399. {
  400.     Track         aTrack = NULL;
  401.     long            aTrackCount = 0;
  402.     long            index;
  403.     OSType        aMediaType;
  404.     Boolean        haveMediaType = false;
  405.     
  406.     aTrackCount = GetMovieTrackCount(theMovie);
  407.     if(aTrackCount == 0)
  408.         return false;                // no tracks in movie
  409.     
  410.     for(index = 1; index <= aTrackCount; index++)
  411.     {
  412.         aTrack = GetMovieIndTrack(theMovie, index);
  413.         GetMediaHandlerDescription( GetTrackMedia(aTrack), &aMediaType, NULL, NULL);
  414.         
  415.         haveMediaType = ( aMediaType == theMediaType);
  416.         if(haveMediaType == true)
  417.             return true;
  418.     }
  419.     return false;            // didn't find the media type track in the movie
  420. }
  421.  
  422.  
  423. /*______________________________________________________________________
  424.     QTUGetTrackRect - Get the Rect of a specified  track.
  425.  
  426. pascal Rect QTUGetTrackRect(Track theTrack)
  427.  
  428. theTrack                track we are interested in concerning the rect information
  429.  
  430. DESCRIPTION
  431.     QTUMediaTypeInTrack will take a (visual) track and return the track's Rect boundaries that 
  432.     could be used later for various calculations of the visual track geometries. Note that
  433.     this Rect is meaningful with video tracks (and any other tracks that have geometrical
  434.     dimensions, otherwise this function will return a rect with zero values.
  435. */
  436.  
  437. pascal OSErr QTUGetTrackRect(Track theTrack, Rect *theRect)
  438. {
  439.     OSErr    anErr = noErr;
  440.     Fixed    aTrackHeight;
  441.     Fixed    aTrackWidth;
  442.  
  443.     theRect->top = 0; theRect->left = 0; theRect->bottom = 0; theRect->right = 0;
  444.     
  445.     DebugAssert(theTrack != NULL);
  446.     if(theTrack == NULL)
  447.         return invalidTrack;
  448.         
  449.     GetTrackDimensions(theTrack, &aTrackHeight, &aTrackWidth);
  450.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  451.     if(anErr != noErr)
  452.         return anErr;
  453.     
  454.     theRect->right = Fix2Long(aTrackWidth);
  455.     theRect->bottom = Fix2Long(aTrackHeight);
  456.     
  457.     return anErr;
  458. }
  459.  
  460.  
  461. /*______________________________________________________________________
  462.     QTUGetVideoMediaPixelDepth - Return the pixel depth of the video media (sample).
  463.  
  464. pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index)
  465.  
  466. theMedia            visual media we want to test concerning pixel depths
  467. index                   index into the media sample we are interested in
  468.  
  469. DESCRIPTION
  470.     QTUGetVideoMediaPixelDepth will take a specified video media and an index into the media 
  471.     samples, and look up the pixel depth for the video sample.
  472. */
  473.  
  474. pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index)
  475. {
  476.     OSErr                                 anErr = noErr;
  477.     short                                 aPixelDepth;
  478.     SampleDescriptionHandle    anImageDesc = NULL;
  479.     OSType                                 mediaType;
  480.     
  481.     DebugAssert(theMedia != NULL);
  482.     DebugAssert(index > 0);
  483.     
  484.     // Test if we are indeed dealing with video media.
  485.     GetMediaHandlerDescription(theMedia, &mediaType, NULL, NULL);
  486.     if(mediaType != VideoMediaType)
  487.         return 0;
  488.         
  489.     anImageDesc = (SampleDescriptionHandle)NewHandle(sizeof(Handle)); DebugAssert(anImageDesc != NULL);
  490.     if(anImageDesc == NULL)
  491.         return 0;
  492.     
  493.     GetMediaSampleDescription(theMedia, index, anImageDesc);
  494.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  495.     
  496.     aPixelDepth = (* (ImageDescriptionHandle)anImageDesc)->depth;
  497.     
  498.     DisposeHandle((Handle)anImageDesc);
  499.     
  500.     return aPixelDepth;
  501. }
  502.  
  503.  
  504. /*______________________________________________________________________
  505.     QTUCountMediaSamples - Count the amount of known media samples in a movie.
  506.  
  507. pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType)
  508.  
  509. theMovie                    the movie with the track(tracks).    
  510. theMediaType            the type of media we are interested in (video, sound and so on)
  511.  
  512. DESCRIPTION
  513.     QTUCountMediaSamples will take a specified movie and a media type, and calculate the amount 
  514.     of samples of this particular type. It could be used to find the total amount of video frames in a 
  515.     movie, or sound samples and so on.
  516.  
  517.     Note that if the movie is long, it will take a long time to go through all the samples, especially 
  518.     in the case of sound samples.
  519.  
  520. EXAMPLE:
  521.     nFrames = QTUCountMediaSamples(aSourceMovie, VideoMediaType); 
  522.  
  523. ISSUES
  524.     This function could be modified to count other types of samples by changing the flags definitions 
  525.     (nextTimeSyncSample for key frames and so on).
  526. */
  527.  
  528. pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType)
  529. {
  530.     long                 numFrames = 0;
  531.     short             flags = nextTimeMediaSample + nextTimeEdgeOK;
  532.     TimeValue        aDuration = 0;
  533.     TimeValue     theTime = 0;
  534.     
  535.     GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
  536.     if(theTime == -1) return numFrames;
  537.  
  538.     flags = nextTimeMediaSample; // Don't include the  nudge after the first interesting time.
  539.     
  540.     while(theTime != -1)  // When the returned time equals -1, then there were no more interesting times.
  541.     {
  542.         numFrames++;
  543.         GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration);
  544.     }
  545.     
  546.     return numFrames;
  547. }
  548.  
  549.  
  550. /*______________________________________________________________________
  551.     QTUGetDurationOfFirstMovieSample - Return the time value of the first sample of a certain 
  552.     media type.
  553.  
  554. pascal TimeValue  QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType)
  555.  
  556. theMovie                        the movie with the media track
  557. theMediaType                specified media type (VideoMediaType, SoundMediaType and so on)
  558.  
  559. DESCRIPTION
  560.     QTUGetDurationOfFirstMovieSample returns the duration of the first sample of a certain media 
  561.     in the movie. If there is no such sample, the duration is 0.
  562.  
  563.     This function could be used in known cases where all the samples are assumed to be of the same 
  564.     duration. For instance in such cases the frame count could be calculated as:
  565.  
  566.     framecount =
  567.              GetMovieDuration(theMovie)/QTUGetDurationofFirstMovieSample(theMovie, VideoMediaType);
  568.  
  569. */
  570.  
  571. pascal TimeValue  QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType)
  572. {
  573.     OSErr             anErr = noErr;
  574.     TimeValue        interestingDuration = 0;
  575.     short            timeFlags = nextTimeMediaSample+nextTimeEdgeOK;
  576.  
  577.     GetMovieNextInterestingTime(theMovie, timeFlags, (TimeValue)1, &theMediaType, 0, 
  578.                                                     fixed1, NULL, &interestingDuration);
  579.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  580.  
  581.     return interestingDuration;
  582. }
  583.  
  584.  
  585. /*______________________________________________________________________
  586.     QTUCountMaxSoundRate - Calculate the max sound data rate of a possible sound track
  587.    in the movie.
  588.  
  589. pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate)
  590.  
  591. theMovie                        the movie with the sound track(tracks).    
  592. theMaxSoundRate            the final returned value
  593.  
  594. DESCRIPTION
  595.     QTUCountMaxSoundRate (taken from the ConvertToMovieJr file) is a simple function that tries
  596.     to figure out the maximum sound track rate. This is done by looking at all of the sound tracks
  597.     in the source movie, and using the one with the highest sample rate (11khz, 22khz and so on),
  598.  
  599.     This number could then be used for calculating the maximum data rate by extracting the sound rate and 
  600.     this way we get a loose estimation how much is left for the video data rate.
  601.     
  602.     This is just an approximation, and a better function should take into account non-overlapping
  603.     sound tracks, stereo sound data rates, compressed sound tracks and so on.
  604. */
  605.  
  606. pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate)
  607. {
  608.     OSErr    anErr = noErr;
  609.     short     index, trackCount;
  610.     
  611.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  612.     *theMaxSoundRate = 0; // just for security we place this value in here
  613.     
  614.     trackCount = GetMovieTrackCount(theMovie);
  615.     
  616.     for(index = 1; index <= trackCount; index++)
  617.     {
  618.         OSType     aTrackType;
  619.         Track        aTrack = NULL;
  620.         Media        aMedia = NULL;
  621.         
  622.         aTrack = GetMovieIndTrack(theMovie, index);  DebugAssert(aTrack != NULL);
  623.         aMedia = GetTrackMedia(aTrack); DebugAssert(aMedia != NULL);
  624.         anErr = GetMoviesError();  DebugAssert(anErr == noErr);
  625.         if(anErr != noErr) return anErr;
  626.         
  627.         GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0);
  628.         if(aTrackType == SoundMediaType)
  629.         {
  630.             long aRate;
  631.             SampleDescriptionHandle aDesc = NULL;
  632.             
  633.             aDesc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription)); DebugAssert(aDesc != NULL);
  634.             GetMediaSampleDescription(aMedia, 1, aDesc);
  635.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  636.             if(anErr != noErr)
  637.             {
  638.                 DisposeHandle((Handle)aDesc);
  639.                 continue;
  640.             }
  641.             
  642.             aRate = (*(SoundDescriptionHandle)aDesc)->sampleRate >> 16;
  643.             if(aRate > *theMaxSoundRate)
  644.                 *theMaxSoundRate = aRate;
  645.         }
  646.     }
  647.     return anErr;
  648. }
  649.  
  650.  
  651.  
  652. /*______________________________________________________________________
  653.     QTUGetMovieFrameCount - Return the amount of frames in the movie based on frame rate estimate.
  654.  
  655. pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate)
  656.  
  657. theMovie                    the movie we want to calculate the frame count for.            
  658. theFrameRate            the expected frame rate of the movie
  659.  
  660. DESCRIPTION
  661.     QTUGetMovieFrameCount is a simple operation that takes into account the duration of the movie,
  662.     the time scale and a suggested frame rate, and based on this will calculate the 
  663.     amount of frames needed in the movie. We assume that the frame rate will be uniform in the movie.
  664. */
  665.  
  666. pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate)
  667. {
  668.     long         frameCount, duration, timescale;
  669.     float     exactFrames;
  670.     
  671.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  672.  
  673.     duration         = GetMovieDuration(theMovie);
  674.     timescale         = GetMovieTimeScale(theMovie);
  675.     exactFrames    = (float)duration * theFrameRate;
  676.     
  677.     frameCount    = exactFrames / timescale / 65536;
  678.     
  679.     if(frameCount == 0)
  680.         frameCount = 1;            // we got to have at least one frame
  681.     
  682.     return frameCount;
  683. }
  684.  
  685.  
  686. /*______________________________________________________________________
  687.     QTUCopySoundTracks - Copy any sound track from the source movie to the destination movie.
  688.  
  689. pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie)
  690.  
  691. aSourceMovie                 movie from which to copy the sound tracks            
  692. aDestinationMovie             movie to which we will copy the sound tracks.    
  693.  
  694. DESCRIPTION
  695.     QTUCopySoundTracks will take any sound tracks from the source movie, and copy these over to the
  696.     destination movie. The destination movie might have no sound track, or then these tracks are 
  697.     added to the existing sound tracks.
  698. */
  699.  
  700. pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie)
  701. {
  702.     OSErr     anErr = noErr;
  703.     long        trackCount, index;
  704.     
  705.     DebugAssert(theSrcMovie != NULL); if(theSrcMovie == NULL) return invalidMovie;
  706.     DebugAssert(theDestMovie != NULL); if(theDestMovie == NULL) return invalidMovie;
  707.  
  708.     trackCount = GetMovieTrackCount(theSrcMovie);
  709.     
  710.     // Loop through each track, look for sound tracks.
  711.     for(index = 1; index <= trackCount; index++)
  712.     {
  713.         OSType aTrackType;
  714.         Track    aSrcTrack, aDestTrack;
  715.         Media    aSrcMedia, aDestMedia;
  716.         
  717.         aSrcTrack = GetMovieIndTrack(theSrcMovie, index);            // get next track and media
  718.         aSrcMedia = GetTrackMedia(aSrcTrack);
  719.         anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  720.         if(anErr != noErr) return anErr;
  721.         
  722.         // try to find sound tracks/media
  723.         GetMediaHandlerDescription(aSrcMedia, &aTrackType, 0, 0);
  724.         if(aTrackType == SoundMediaType)
  725.         {
  726.             // Create the track for the sound media.
  727.             aDestTrack = NewMovieTrack(theDestMovie, 0, 0, GetTrackVolume(aSrcTrack));
  728.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  729.             if(anErr != noErr) return anErr;
  730.             
  731.             // Create a media for the sound track and prepare this media for editing.
  732.             aDestMedia = NewTrackMedia(aDestTrack, SoundMediaType, GetMediaTimeScale(aSrcMedia), 0, 0);
  733.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  734.             if(anErr != noErr) return anErr;
  735.             
  736.             anErr = BeginMediaEdits(aDestMedia); DebugAssert(anErr == noErr);
  737.             if(anErr != noErr) return anErr;
  738.             
  739.             // Insert the new track into the destination movie starting at time zero and
  740.             // lasting for the entire duration of the movie.
  741.             InsertTrackSegment(aSrcTrack, aDestTrack, 0 , GetTrackDuration(aSrcTrack), 0);
  742.             anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  743.             if(anErr != noErr) return anErr;
  744.             
  745.             // We've done editing the media
  746.             EndMediaEdits(aDestMedia);
  747.         }
  748.     }
  749.     return anErr;
  750. }
  751.  
  752.  
  753.  
  754. /*______________________________________________________________________
  755.     QTUPrintMoviePICT - Print the existing movie frame pict.
  756.  
  757. pascal Boolean QTUPrintMoviePICTr(Movie theMovie, short x, short y,  long PICTUsed)
  758.  
  759. theMovie                    movie that has the poster        
  760. x,y                            starting point coordinates where to place the poster on paper
  761.  
  762. DESCRIPTION
  763.     QTUPrintMoviePICT is a simple function showing how to print movie posters. 
  764.  
  765. ISSUES
  766.     Note that in a real application we should put the PrStlDialog code into the Print Setup… menu
  767.     function. The reason it's inside this function is that we use this code for quick testing of 
  768.     printing.
  769. */
  770.  
  771. pascal OSErr QTUPrintMoviePICT(Movie theMovie, short x, short y, long PICTUsed)
  772. {
  773.     OSErr        anErr = noErr;
  774.     PicHandle     aPictHandle = NULL;
  775.     THPrint        aTHPrint = NULL;
  776.     GrafPtr         aSavedPort;
  777.     TPPrPort    aPrintPort;
  778.     Boolean     aResult;
  779.     Boolean        isPrinting = false;
  780.     Rect            aPictRect;
  781.     
  782.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  783.     
  784.     GetPort(&aSavedPort);
  785.  
  786. // Get the PICT to be printed, either the poster pict or the current frame pict.
  787.     switch(PICTUsed)
  788.     {
  789.         case kPrintFrame:
  790.             aPictHandle = GetMoviePict(theMovie, GetMovieTime(theMovie, 0L));
  791.             break;
  792.             
  793.  
  794.         case kPrintPoster:
  795.             aPictHandle = GetMoviePosterPict(theMovie); 
  796.             break;
  797.  
  798.         default:
  799.             DebugAssert("Should not happen, incorrect constant used"); goto Closure;
  800.     }
  801.  
  802.     if(aPictHandle == NULL) goto Closure;
  803.  
  804.  
  805. // Get the Print record.
  806.     aTHPrint = (THPrint) NewHandleClear(sizeof(TPrint)); DebugAssert(aTHPrint != NULL);
  807.     if(aTHPrint == NULL) goto Closure;
  808.  
  809.     PrOpen(); isPrinting = true;
  810.     anErr = PrError(); DebugAssert(anErr == noErr);
  811.         if(anErr != noErr) goto Closure;
  812.  
  813.     PrintDefault(aTHPrint);
  814.  
  815. // Move this to Print Setup…if you want to make this look really cool.    
  816.     aResult = PrStlDialog(aTHPrint); DebugAssert(aResult == true);
  817.     if(!aResult) goto Closure;
  818.     
  819.     aResult = PrJobDialog(aTHPrint); DebugAssert(aResult == true);
  820.     if(!aResult) goto Closure;
  821.     
  822.     aPrintPort = PrOpenDoc(aTHPrint, NULL, NULL); DebugAssert(aPrintPort != NULL);
  823.     PrOpenPage(aPrintPort, NULL);
  824.     anErr = PrError(); DebugAssert(anErr == noErr);
  825.     if(anErr != noErr) goto Closure;
  826.     
  827. // Print at x,y position
  828.     aPictRect =  (*aPictHandle)->picFrame;
  829.     OffsetRect(&aPictRect, x - aPictRect.left,  y  - aPictRect.top);
  830.     
  831.     DrawPicture(aPictHandle, &aPictRect);
  832.  
  833. // If you want to do additional drawing, do it here.
  834.     
  835.     PrClosePage(aPrintPort);
  836.     PrCloseDoc(aPrintPort);
  837.     anErr = PrError(); DebugAssert(anErr == noErr);
  838.     if(anErr != noErr) goto Closure;
  839.     
  840.     if(( *aTHPrint)->prJob.bJDocLoop == bSpoolLoop)
  841.         PrPicFile(aTHPrint, NULL, NULL, NULL, NULL);
  842.     
  843. // Our closure handling.
  844. Closure:
  845.     SetPort(aSavedPort);
  846.     
  847.     if(isPrinting) PrClose();
  848.     if(aPictHandle) KillPicture(aPictHandle);
  849.     if(aTHPrint) DisposeHandle((Handle)aTHPrint);
  850.     return anErr;
  851. }
  852.  
  853.  
  854. /*______________________________________________________________________
  855.     QTUCalculateMovieMemorySize - Calculate how much memory a movie takes in the app heap.
  856.  
  857. pascal OSErr QTUCalculateMovieMemorySize(Movie theMovie, long *theSize)
  858.  
  859. theMovie                        movie we want to know the size of in the current application heap
  860. theSize                            pointer to a long that will contain the movie size in bytes
  861.  
  862. DESCRIPTION
  863.     QTUCalculateMovieMemorySize will return the amount of bytes it is allocating as a handle
  864.     in the current application heap, if there's not enough space for a temp handle, or if anything
  865.     else fails, the function will return 0L in theSize (and the OSErr).
  866.  
  867. ISSUES
  868.     Note that possible movie controllers associated with the movie and other constructs will eat up
  869.     memory. What you could do is to do a MacsBug HT before the movie or movies are opened, 
  870.     check the amount of free space, and HT after the movies are opened, figure out the movie sizes 
  871.     using the function below, and calculate the delta from these values.
  872. */
  873.  
  874. pascal OSErr QTUCalculateMovieMemorySize(Movie theMovie, long *theSize)
  875. {
  876.     OSErr     anErr = noErr;
  877.     Handle    tempHandle = NULL;
  878.  
  879.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  880.  
  881.     *theSize = 0L;
  882.  
  883.     tempHandle = NewHandle(sizeof(Movie)); DebugAssert(tempHandle != NULL);
  884.     anErr = MemError(); DebugAssert(anErr == noErr);
  885.     if(anErr != noErr || tempHandle == NULL) goto Closure;
  886.  
  887.     anErr =  PutMovieIntoHandle(theMovie, tempHandle); DebugAssert(anErr == noErr);
  888.  
  889.     if(anErr == noErr)    
  890.             *theSize = GetHandleSize(tempHandle);
  891.  
  892. Closure:
  893.     if(tempHandle != NULL) DisposeHandle(tempHandle);
  894.  
  895.     return anErr;
  896. }
  897.  
  898.  
  899. /*______________________________________________________________________
  900.     QTULoadWholeMovieToRAM - Load the entire active segment (movie) into RAM
  901.  
  902. pascal OSErr    QTULoadWholeMovieToRAM(Movie theMovie)
  903.  
  904. theMovie                        movie we want to know the size of in the current application heap.
  905.  
  906. DESCRIPTION
  907.     QTULoadWholeMovieToRAM is an example of how to load movie information into RAM. In
  908.     this case we will load the entire movie, or in other words all the active segments.
  909.  
  910. ISSUES
  911.     The most likely error returned from this function is due to lack of memory.  You could 
  912.     also fine tune this function by loading partial data based on time or track specifications.
  913.  
  914.     Loading whole movies is OK if the movies are small, have few tracks with little info (text
  915.     tracks, music tracks and so on), there's a certain performance need  why it makes sense 
  916.     to keep the movie in RAM (looping, other issues), and in general if you know why it's needed.
  917. */
  918.  
  919. pascal OSErr    QTULoadWholeMovieToRAM(Movie theMovie)
  920. {
  921.     OSErr anErr = noErr;
  922.  
  923.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  924.  
  925.     GoToBeginningOfMovie(theMovie);
  926.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  927.     if (anErr != noErr) return anErr;
  928.  
  929.     anErr = LoadMovieIntoRam(theMovie, GetMovieTime(theMovie, NULL), GetMovieDuration(theMovie), 0);
  930.  
  931.     return anErr;
  932. }
  933.  
  934.  
  935. /*______________________________________________________________________
  936.     QTUPlayMovieSound - Play the movie sound track using the Sound Manager.
  937.  
  938. pascal OSErr QTUPlayMovieSound(Movie theMovie)
  939.  
  940. theMovie                        movie wherefrom we extract the sound resource
  941.  
  942. DESCRIPTION
  943.     QTUPlayMovieSound is an example of how to extract the 'snd ' sound resource from the 
  944.     first sound track in a movie, and play this track back using the Sound Manager. This
  945.     sound resource could also be retrieved, or otherwised used in other instances. Note that
  946.     this function is more of an example of how to retrieve sound from a movie; you might
  947.     want to control the start point, duration, and sound track extracted.
  948.  
  949. */
  950.  
  951. pascal OSErr QTUPlayMovieSound(Movie theMovie)
  952. {
  953.     OSErr    anErr = noErr;
  954.     Handle     tempHandle  = NewHandle(1);
  955.     
  956.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie;
  957.  
  958.     // Extract first sound track.
  959.     anErr = PutMovieIntoTypedHandle(theMovie, (Track)0, 'snd ', tempHandle, 0, GetMovieDuration(theMovie),
  960.                                                         0, (ComponentInstance)0); DebugAssert(anErr == noErr);
  961.     if(anErr != noErr) goto Closure;
  962.     anErr = MemError(); DebugAssert(anErr == noErr);
  963.     if(anErr != noErr) goto Closure;
  964.  
  965.     // Play sound resource async.
  966.     anErr = SndPlay(0L, (SndListHandle)tempHandle, TRUE);     DebugAssert(anErr == noErr);
  967.  
  968. Closure:
  969.     if(tempHandle) DisposeHandle(tempHandle);
  970.  
  971.     return anErr;
  972. }
  973.  
  974.  
  975. /*______________________________________________________________________
  976.     QTUDrawVideoFrameAtTime - Display a movie video frame at specified movie time.
  977.  
  978. pascal OSErr QTUDrawVideoFrameAtTime(Movie theMovie, TimeValue atTime)
  979.  
  980. theMovie                        movie we are using
  981. atTime                            time value in the movie for the video frame we want to display
  982.  
  983. DESCRIPTION
  984.     QTUDrawVideoFrameAtTime will display a specific video sample (or frame) at a specified time.
  985.     In other words if we want to draw a frame at time point 600, the nearest video frame
  986.     corresponding to this time value will be shown. 
  987.  
  988.     We assume that the movie is properly set, and is using a correct portRect or GWorld.
  989.  
  990. */
  991.  
  992. pascal OSErr QTUDrawVideoFrameAtTime(Movie theMovie, TimeValue atTime)
  993. {
  994.     TimeValue totalTime;
  995.     
  996.     OSErr anErr = noErr;
  997.     DebugAssert(theMovie != NULL); if(theMovie == NULL) return paramErr;
  998.     
  999.     totalTime = GetMovieDuration(theMovie);
  1000.     if(atTime > totalTime) return paramErr;
  1001.     
  1002.     if(atTime == 0L) {
  1003.         GoToBeginningOfMovie(theMovie); anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1004.         if(anErr) goto Closure;
  1005.     }
  1006.     else {
  1007.         SetMovieTimeValue(theMovie, atTime); anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1008.         if(anErr) goto Closure;
  1009.     }
  1010.     
  1011.     anErr = UpdateMovie(theMovie);  DebugAssert(anErr == noErr);
  1012.     if(anErr) goto Closure;
  1013.     
  1014.     MoviesTask(theMovie, 0L); anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1015.  
  1016. Closure:    
  1017.     return anErr;
  1018. }
  1019.  
  1020.  
  1021.  
  1022. /*______________________________________________________________________
  1023.     QTUScrollToNextVideoSample -  Scroll offscreen from one video sample to the next.
  1024.  
  1025. pascal OSErr QTUScrollToNextVideoSample(Movie theMovie, TimeValue fromTimePoint, TimeValue toTimePoint)
  1026.  
  1027. fromTimePoint                        starting time value of the first video sample (frame)
  1028. toTimePoint                            end time value for the second video sample (frame)
  1029.  
  1030. DESCRIPTION
  1031.     QTUScrollToNextVideoSample will scroll from one video sample to the other one using offscreen
  1032.     GWorlds where the effect is created. 
  1033.  
  1034.     We assume that the movie is properly set, and that the movie will use a proper portRect or GWorld.
  1035.  
  1036. CREDITS
  1037.     Presto Studios for the core idea and some of the code below.
  1038.  
  1039. */
  1040.  
  1041. pascal OSErr QTUScrollToNextVideoSample(Movie theMovie, TimeValue fromTimePoint, TimeValue toTimePoint) 
  1042. {
  1043.     OSErr                 anErr = noErr;
  1044.     GWorldPtr            frameGWorld1 = NULL;
  1045.     GWorldPtr            frameGWorld2 = NULL;
  1046.     PixMapHandle    pixMap1 = NULL;
  1047.     PixMapHandle    pixMap2    = NULL;
  1048.     CGrafPtr            aSavedPort, moviePort;
  1049.     GDHandle            aSavedGDevice, movieGDevice;
  1050.     CTabHandle        colorTable;
  1051.     short                screenDepth = 0;
  1052.     short                screenSize = 0;
  1053.     Rect                    movieRect, sourceRect, destinationRect;
  1054.     RgnHandle            scrollRegion = NULL;
  1055.     RgnHandle            clipRegion = NULL;
  1056.     short                nSteps;
  1057.         
  1058.     DebugAssert(theMovie != NULL); if(theMovie == NULL) goto Closure;
  1059.     
  1060.     //• Store away current portrect and Gdevice, get pixel sizes and color table for GWorld creation purposes.
  1061.     GetGWorld(&aSavedPort, &aSavedGDevice);
  1062.     
  1063.     GetMovieGWorld(theMovie, &moviePort, &movieGDevice);
  1064.     screenDepth = (**(**aSavedGDevice).gdPMap).pixelSize;
  1065.     colorTable = (**(**aSavedGDevice).gdPMap).pmTable;
  1066.     
  1067.     //• Adjust the movie box.
  1068.      GetMovieBox(theMovie, &movieRect);  // If you want to offset by 10,10: OffsetRect(&movieRect, 10 -movieRect.left, 10 - movieRect.top);
  1069.      SetMovieBox(theMovie, &movieRect);
  1070.     
  1071.     //• Create two GWorlds for dual screen writing and possible scrolling transition effects. Lock down pixmaps.
  1072.     anErr = NewGWorld(&frameGWorld1, screenDepth, &movieRect, colorTable, NULL, 0); DebugAssert(anErr == noErr);
  1073.     if(anErr != noErr) goto Closure;
  1074.     anErr = NewGWorld(&frameGWorld2, screenDepth, &movieRect, colorTable, NULL, 0); DebugAssert(anErr == noErr);
  1075.     if(anErr != noErr) goto Closure;
  1076.     
  1077.     pixMap1 = GetGWorldPixMap(frameGWorld1);  if(!LockPixels(pixMap1)) goto Closure;
  1078.     pixMap2 = GetGWorldPixMap(frameGWorld2);  if(!LockPixels(pixMap2)) goto Closure;
  1079.     
  1080.     //• Draw first video sample (frame) to GWorld number 1.
  1081.     SetMovieGWorld(theMovie, frameGWorld1, GetGWorldDevice(frameGWorld1));
  1082.     SetMovieTimeValue(theMovie, fromTimePoint);
  1083.     UpdateMovie(theMovie); MoviesTask(theMovie, 0);
  1084.     
  1085.     //• Draw second video sample (frame) to GWorld number 2.
  1086.     SetMovieGWorld(theMovie, frameGWorld2, GetGWorldDevice(frameGWorld2));
  1087.     SetMovieTimeValue(theMovie, toTimePoint); 
  1088.     UpdateMovie(theMovie); MoviesTask(theMovie, 0);
  1089.     
  1090.     //• Create scroll region and store away the current clip region.
  1091.     scrollRegion = NewRgn(); DebugAssert(scrollRegion != NULL);
  1092.     if(scrollRegion == NULL) goto Closure;
  1093.     
  1094.     clipRegion = NewRgn(); DebugAssert(clipRegion != NULL);
  1095.     if(clipRegion == NULL) goto Closure;
  1096.     GetClip(clipRegion); ClipRect(&movieRect);
  1097.     
  1098.     //• Create the scroll effect.
  1099.     screenSize = movieRect.right - movieRect.left;
  1100.     
  1101.     for(nSteps = 10; nSteps <= screenSize; nSteps += 10)  {
  1102.         SetGWorld( frameGWorld1, NULL);
  1103.         
  1104.         ScrollRect(&movieRect, -10, 0, scrollRegion);
  1105.         SetRect(&sourceRect, movieRect.left, movieRect.top, 
  1106.                 movieRect.left + nSteps, movieRect.bottom);
  1107.         SetRect(&destinationRect, movieRect.right - nSteps,
  1108.                 movieRect.top, movieRect.right, movieRect.bottom);
  1109.         
  1110.         CopyBits( (BitMap *) *pixMap2, (BitMap *) *pixMap1, &sourceRect, &destinationRect,
  1111.                     srcCopy, NULL );                // blit from frameGWorld2 to frameGWorld1
  1112.         DebugAssert(QDError() == noErr);
  1113.         
  1114.         SetGWorld(aSavedPort, aSavedGDevice);
  1115.         CopyBits( (BitMap *) *pixMap1, (BitMap *) &aSavedPort->portPixMap, &movieRect,
  1116.                     &movieRect, srcCopy, NULL );       // blit from frameGWorld1 to screen pixmap
  1117.         DebugAssert(QDError() == noErr);
  1118.     }
  1119.  
  1120.     //• Unlock pixels, restore the original clip region.    
  1121.     UnlockPixels(pixMap1); UnlockPixels(pixMap2);
  1122.     SetClip(clipRegion);
  1123.     
  1124.     //• Closure. Clean up if we have handles.
  1125. Closure:    
  1126.     if(frameGWorld1 != NULL)         DisposeGWorld(frameGWorld1);
  1127.     if(frameGWorld2 != NULL)         DisposeGWorld(frameGWorld2);
  1128.     if(scrollRegion != NULL)             DisposeRgn(scrollRegion);
  1129.     if(clipRegion != NULL)                 DisposeRgn(clipRegion);
  1130.  
  1131.     SetMovieGWorld(theMovie, moviePort, movieGDevice);
  1132.     SetGWorld(aSavedPort, aSavedGDevice);    
  1133.  
  1134.     return anErr;
  1135. }
  1136.  
  1137.  
  1138. /*______________________________________________________________________
  1139.     QTUGetStartPointOfFirstVideoSample -  Get time value of first sample in the movie.
  1140.  
  1141. TimeValue QTUGetStartPointOfFirstVideoSample(Movie theMovie) 
  1142.  
  1143. theMovie                    movie we are interested in
  1144. startPoint                    will contain the value of the start point, if the function fails it will contain
  1145.                                 -1.
  1146.  
  1147. DESCRIPTION
  1148.     QTUGetStartPointOfFirstVideoSample will return the time value of the first video sample found in the
  1149.     movie in the startPoint parameter. If the function fails, startPoint will contain -1 and the OSErr is 
  1150.     also returned.
  1151. */
  1152.  
  1153. pascal OSErr QTUGetStartPointOfFirstVideoSample(Movie theMovie, TimeValue *startPoint) 
  1154. {
  1155.     OSErr    anErr = noErr;
  1156.     OSType    media = VideoMediaType;
  1157.     
  1158.     *startPoint = -1;
  1159.  
  1160.     GetMovieNextInterestingTime(theMovie, nextTimeMediaSample+nextTimeEdgeOK, (TimeValue)1, &media, 0, 
  1161.                                                     fixed1, startPoint, NULL);
  1162.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1163.  
  1164.     return anErr;
  1165. }
  1166.  
  1167.  
  1168. // IMAGE COMPRESSION MANAGER
  1169.  
  1170. /*______________________________________________________________________
  1171.     QTUHasCodecLossLessQuality - Test if a specific codec has a lossless mode in a specific bit depth.
  1172.  
  1173. Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth)
  1174.  
  1175. theCodec                        specifies the Codec Type ('jpeg, 'rle ' and so on).
  1176. thePixelDepth                specifies the bit depth (8, 24, 30 and so on). See NIM:QuickTime, page 
  1177.                                     3-70 for more details.
  1178.  
  1179. DESCRIPTION
  1180.     QTUHasCodecLossLessQuality will test if a specific codec has a lossless spatial compression 
  1181.     quality at a certain bit depth. Note that we are not testing the temporal compression qualities.
  1182.  
  1183. EXAMPLE OF USE:
  1184.     if(QTUHasCodecLossLessQuality('jpeg', 32))  
  1185.         printf("JPEG has lossless spatial compression\n");
  1186.     else
  1187.         printf("JPEG has NOT lossless spatial compression\n");
  1188.  
  1189. */
  1190.  
  1191. Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth)
  1192. {
  1193.     OSErr     anErr = noErr;
  1194.     CodecQ    aSpatialQuality = codecLosslessQuality;
  1195.  
  1196.     anErr = GetCompressionTime(NULL, NULL, thePixelDepth, theCodec, anyCodec, &aSpatialQuality,
  1197.                         NULL, NULL); DebugAssert(anErr == noErr);
  1198.     
  1199.     if(aSpatialQuality == codecLosslessQuality)    // still the same?
  1200.         return true;
  1201.     else
  1202.         return false;
  1203. }
  1204.  
  1205.  
  1206.  
  1207. // MOVIE CONTROLLER FUNCTIONS
  1208.  
  1209.  
  1210. /*______________________________________________________________________
  1211.     QTUPlayMovieWithMC - Play a specific movie when using movie controllers.
  1212.  
  1213. pascal OSErr QTUPlayMovieWithMC( MovieController mc)
  1214.  
  1215. mc                        specified movie controller to be used
  1216.  
  1217. DESCRIPTION
  1218.     Playmovie will start a movie using a moviecontroller and a specified movie. Note that it also  
  1219.     does a preroll of the movie for performance reasons. 
  1220.  
  1221. */
  1222.  
  1223. pascal OSErr QTUPlayMovieWithMC(MovieController mc)
  1224. {
  1225. // Play normal speed forward, taking into account the possibility 
  1226. // of a movie with a nonstandard PreferredRate.
  1227.     OSErr    anErr = noErr;
  1228.     Fixed     aRate;
  1229.     Movie    aMovie;
  1230.  
  1231.     aMovie = MCGetMovie(mc);
  1232.  
  1233.     aRate= GetMoviePreferredRate(aMovie);
  1234.     anErr = QTUPrerollMovie(aMovie);  // Important: Preroll the movie here.
  1235.     DebugAssert(anErr == noErr);
  1236.  
  1237.     if(anErr == noErr)
  1238.     {
  1239.         MCDoAction(mc, mcActionPlay, (void *)aRate);  // note last value
  1240.     }
  1241.     
  1242.     return anErr;
  1243. }
  1244.  
  1245.  
  1246. /*______________________________________________________________________
  1247.     QTUDoIgnoreMCDrags - Disable Drag and Drop facilities of the movie controller environment.
  1248.  
  1249. pascal OSErr  QTUDoIgnoreMCDrags(MovieController  mc)
  1250.  
  1251. mc                        is the specified moviecontroller to be used
  1252.  
  1253. DESCRIPTION
  1254.     QTUDoIgnoreMCDrags will ensure that the Drag and Drop functionality is not handled within 
  1255.     the movie specified by the movie controller.
  1256.  
  1257. ISSUES
  1258.     Note that this is a workaround in QT 2.0 (test for QT 2.0 or higher if you want to use
  1259.     the drag-and-drop support in QT), and this function might not be needed in later QT versions.
  1260. */
  1261.  
  1262. pascal OSErr QTUDoIgnoreMCDrags(MovieController  mc)
  1263. {
  1264.    OSErr           anErr = noErr;
  1265.    GWorldPtr  aTempGWorld;
  1266.    Rect             aTempRect = {0, 0, 20, 20};
  1267.    CGrafPtr     aPort;
  1268.  
  1269.    // First create a 1-bit small 20x20 offscreen.
  1270.    anErr = NewGWorld( &aTempGWorld, 1, &aTempRect, NULL, NULL, 0L );
  1271.    DebugAssert(anErr == noErr);
  1272.  
  1273.    if (anErr != noErr)
  1274.    {
  1275.            aPort = MCGetControllerPort(mc);                                    // get the current port
  1276.            MCSetControllerPort(mc, (CGrafPtr)aTempGWorld );        // set mc port to new offscreen
  1277.            MCDoAction(mc, mcActionSetDragEnabled, (void *)false); // don't want dragging
  1278.           MCSetControllerPort(mc, aPort);                                        // restore mc port
  1279.            DisposeGWorld(aTempGWorld);                                            // dispose offscreen
  1280.    }
  1281.    return anErr;
  1282. }
  1283.  
  1284.  
  1285. /*______________________________________________________________________
  1286.     QTUPointInMC - Test if a point is placed in the movie controller rect area or not.
  1287.  
  1288. pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where)
  1289.  
  1290. mc                            is the specified moviecontroller to be used
  1291. theWindow                window used for testing for the hit point
  1292. where                        hit point
  1293.  
  1294. DESCRIPTION
  1295.     QTUPointInMC is a simple test to check where the mouse was clicked inside the window
  1296.     with a movie controller, returns true of the mouse click was inside the movie controller
  1297.     rect. See Peter Hoddie's article in develop# 18 for more details (code is from him as well).
  1298. */
  1299.  
  1300. pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where)
  1301. {
  1302.     RgnHandle        aRegion;
  1303.     Boolean            result = false;
  1304.     
  1305.     aRegion = MCGetWindowRgn(mc, theWindow);
  1306.        DebugAssert(aRegion != NULL);
  1307.     
  1308.     if(aRegion != NULL)
  1309.     {
  1310.         result = PtInRgn(where, aRegion);
  1311.         DisposeRgn(aRegion);
  1312.     }
  1313.     
  1314.     return result;
  1315. }
  1316.  
  1317.  
  1318. /*______________________________________________________________________
  1319.     QTUSelectAllMovie - Select the whole movie time duration with the controller.
  1320.  
  1321. pascal OSErr QTUSelectAllMovie(MovieController mc)
  1322.  
  1323. mc                        is the specified moviecontroller to be used
  1324.  
  1325. DESCRIPTION
  1326.     QTUSelectAllMovie is an example how to select the whole movie duration using the movie
  1327.     controller, this function could be used for Select All menu entries and similar cases.
  1328. */
  1329.  
  1330. pascal OSErr QTUSelectAllMovie(MovieController mc)
  1331. {
  1332.     OSErr             anErr = noErr;
  1333.     TimeRecord  aTimeRecord;
  1334.     Movie             aMovie = NULL;
  1335.     
  1336.     DebugAssert(mc != NULL);
  1337.     if(mc == NULL) return paramErr;
  1338.     
  1339.     aMovie = MCGetMovie(mc); DebugAssert(aMovie != NULL);
  1340.     if(aMovie == NULL) return paramErr;
  1341.     
  1342.     aTimeRecord.value.hi = 0;
  1343.     aTimeRecord.value.lo = 0;
  1344.     aTimeRecord.base = 0;
  1345.     
  1346.     aTimeRecord.scale = GetMovieTimeScale(aMovie);
  1347.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1348.     if(anErr != noErr) return anErr;
  1349.     
  1350.     anErr = MCDoAction(mc, mcActionSetSelectionBegin, &aTimeRecord);
  1351.     DebugAssert(anErr == noErr);
  1352.     if(anErr != noErr) return anErr;
  1353.     
  1354.     aTimeRecord.value.lo = GetMovieDuration(aMovie);
  1355.     anErr = GetMoviesError(); DebugAssert(anErr == noErr);
  1356.     if(anErr != noErr) return anErr;
  1357.     
  1358.     anErr = MCDoAction(mc, mcActionSetSelectionDuration, &aTimeRecord);
  1359.     DebugAssert(anErr == noErr);
  1360.     
  1361.     return anErr;
  1362. }
  1363.  
  1364.  
  1365. /*______________________________________________________________________
  1366.      QTUResizeMCActionFilter - Example of a movie controller filter that will resize the window 
  1367.     where the movie is placed when the controllers themself change. 
  1368.  
  1369. pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void *params, long refCon)
  1370.  
  1371. mc                            specified moviecontroller to be used.
  1372. action                        the action for the mc action filter
  1373. params                        parameters passed with the action
  1374. refCon                      additional long word that could be used for all kinds of purposes
  1375.  
  1376. DESCRIPTION
  1377.     QTUResizeMCActionFilter is an example of how to create a nice movie controller filter that 
  1378.     will handle resizing of the window with the movie, and this will happen every time the controllers
  1379.     themselves change. It's also an example of how to write other kinds of movie controller filters.
  1380. */
  1381.  
  1382. pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void* /*params*/ , long refCon)
  1383. {
  1384.     Rect aMovieBounds;
  1385.     
  1386.     switch(action)
  1387.     {
  1388.         case mcActionControllerSizeChanged:
  1389.             MCGetControllerBoundsRect(mc, &aMovieBounds);
  1390.             SizeWindow((WindowPtr) refCon, aMovieBounds.right - aMovieBounds.left,
  1391.                                 aMovieBounds.bottom - aMovieBounds.top, true);
  1392.             break;
  1393.     }
  1394.         return false;
  1395. }
  1396.  
  1397.  
  1398. /*______________________________________________________________________
  1399.     QTUResizeMCWindow - Resize a window to either normal size, double size or  half of the movie rect size.
  1400.  
  1401. pascal Boolean QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize)
  1402.  
  1403. mc                                specified moviecontroller to be used
  1404. theWindow                    window that will be resized
  1405. theMovieSize                constant that defines what default size we are interested in,  kNormalSize, kHalfSize, kDoubleSize
  1406. originalSize                    the original size of the movie, we need to keep track of this one in order to handle the 
  1407.                                      ambient new sizes (half, double, normal).
  1408.  
  1409. DESCRIPTION
  1410.     QTUResizeMCWindow is an example of a function how to resize the movie window with the controllers.
  1411.     The most common cases is half size, normal size or double size. But nothing hinders to add more sizes
  1412.     into this function. Note that if the movie window is doubled, we will get pixel-doubling by the QuickTime
  1413.     engine.
  1414. */
  1415.  
  1416. pascal OSErr QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize)
  1417. {
  1418.     OSErr         anErr = noErr;
  1419.     Rect             aMovieBounds;
  1420.     GrafPtr     aSavedPort;
  1421.     
  1422.     DebugAssert(mc != NULL); if(mc == NULL) return paramErr;
  1423.     DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr;
  1424.     
  1425.     GetPort(&aSavedPort);
  1426.     SetPort((GrafPtr)theWindow);
  1427.     
  1428.     aMovieBounds.top = 0; aMovieBounds.left = 0;
  1429.  
  1430.     switch(theMovieSize)
  1431.     {
  1432.         case kNormalMovieSize:
  1433.                 MCSetControllerBoundsRect(mc, &originalSize);
  1434.                 SizeWindow(theWindow, originalSize.right, originalSize.bottom, true);
  1435.             break;
  1436.         
  1437.         case kHalfMovieSize:
  1438.                 aMovieBounds.right = (originalSize.right - originalSize.left) / 2;
  1439.                 aMovieBounds.bottom = (originalSize.bottom - originalSize.top) / 2;
  1440.                 MCSetControllerBoundsRect(mc, &aMovieBounds);
  1441.                 SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true);
  1442.             break;
  1443.         
  1444.         case kDoubleMovieSize:
  1445.                 aMovieBounds.right = (originalSize.right - originalSize.left) * 2;
  1446.                 aMovieBounds.bottom = (originalSize.bottom - originalSize.top) * 2;
  1447.                 MCSetControllerBoundsRect(mc, &aMovieBounds);
  1448.                 SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true);
  1449.             break;
  1450.         
  1451.         default:
  1452.             SetPort(aSavedPort);
  1453.             anErr = paramErr;
  1454.     }
  1455.     
  1456.     SetPort(aSavedPort);
  1457.     return anErr;
  1458. }
  1459.  
  1460.  
  1461. /*______________________________________________________________________
  1462.     QTUResizeMCWindow -Change the movie rate using the movie controller. 
  1463.  
  1464. pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate)
  1465.  
  1466. mc                            specified moviecontroller to be used
  1467. theRate                        new rate value, we are using specific constants, see the eQTUMovieRates enum
  1468.                                 in the DTSQTUtilities.h file concerning the values.
  1469.  
  1470. DESCRIPTION
  1471.     QTUMCSetMovieRate will use an existing movie controller and change the rate. This is a very 
  1472.     simple function, but we do have a list of constants that shows the various values that could be used 
  1473.     (eQTUMovieRates, DTSQTUtilities.h), and also it shows that if the rate changes from 0 to something 
  1474.     else, then we need to preroll the movie. The Apple MM Tuner will make sure the movie is prerolled,
  1475.     but we can't assume that every Mac has this extension installed, that's why it's still very important
  1476.     to preroll.
  1477.     
  1478. ISSUES
  1479.     Note that movies have stored preferred rates, so if you want to compensate for this factor you need
  1480.     to read in this value as well before setting a double or half speed value.
  1481. */
  1482.  
  1483. pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate)
  1484. {
  1485.     OSErr     anErr = noErr;
  1486.     Fixed     aRate;
  1487.     
  1488.     DebugAssert(mc != NULL);  
  1489.     if(mc == NULL)
  1490.     {
  1491.         anErr = paramErr; goto Closure;
  1492.     }
  1493.     
  1494.     // Test if the playrate changes from 0 to a non-zero value, if so then preroll the movie.
  1495.     MCDoAction(mc, mcActionGetPlayRate, &aRate);
  1496.     if( (aRate == 0) && (theRate != 0) )
  1497.     {
  1498.         anErr = QTUPrerollMovie(MCGetMovie(mc));            // we are using the DTSQTUtilities function
  1499.         DebugAssert(anErr == noErr);
  1500.         if(anErr != noErr) return anErr;
  1501.     }
  1502.         
  1503.     anErr = MCDoAction(mc, mcActionPlay, (Ptr) theRate); DebugAssert(anErr == noErr);
  1504.  
  1505. Closure:    
  1506.     return anErr;
  1507. }
  1508.  
  1509. // SEQUENCE GRABBER FUNCTIONS
  1510. /*______________________________________________________________________
  1511.     QTUCreateSequenceGrabber - Create an instance of a sequence grabber for specified window.
  1512.  
  1513. pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow)
  1514.  
  1515. theWindow                    window where the sequence grabber will operate
  1516.  
  1517. DESCRIPTION
  1518.     QTUCreateSequenceGrabber will try to open the default sequence grabber component and 
  1519.     make sure this component will work in the GWorld of a specified window. 
  1520.  
  1521.     If we don't find a suitable sequence grabber, or if we encounter problems, we will return NULL.
  1522. */
  1523.  
  1524.  
  1525. pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow)
  1526. {
  1527.     OSErr anErr = noErr;
  1528.     SeqGrabComponent s = NULL;
  1529.  
  1530.     DebugAssert(theWindow != NULL); if(theWindow == NULL) goto Closure;
  1531.  
  1532.     s = OpenDefaultComponent(SeqGrabComponentType, 0);
  1533.  
  1534.     if(s) // we got a valid one
  1535.     {
  1536.         anErr = SGInitialize(s); DebugAssert(anErr == noErr);
  1537.         if(anErr != noErr) goto Closure;
  1538.  
  1539.         anErr = SGSetGWorld(s, (CGrafPtr)theWindow, NULL); DebugAssert(anErr == noErr);
  1540.         if(anErr != noErr) goto Closure;
  1541.     }
  1542.  
  1543.     return s;
  1544. Closure:
  1545.     return NULL;
  1546. }
  1547.  
  1548. /*______________________________________________________________________
  1549.     QTUCreateSGGrabChannels - Create SG channels, video and audio.
  1550.  
  1551. pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage,
  1552.                                                                 SGChannel *theVideoChannel, SGChannel *theSoundChannel)
  1553.  
  1554. s                            current active sequence grabber component instance
  1555. theBounds                the size of the video channel sequence grabber area
  1556. theUsage                any additional flags for the video SG
  1557. theVideoChannel    pointer to the video channel we will receive
  1558. theSoundChannel    pointer to the audio channel we will receive
  1559.  
  1560.  
  1561. DESCRIPTION
  1562.     QTUCreateSGGrabChannels will create video and audio SG channels (SGChannels) using the specified
  1563.     default SG component.
  1564.  
  1565. ISSUES
  1566.     We will terminate whenever we can't properly create  a channel (sound, audio), if you still want to
  1567.     retrieve a valid channel (let's say the sound one is OK while the we can't open an audio one), you
  1568.     could slightly rewrite this code.
  1569. */
  1570.  
  1571. pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage,
  1572.                                                                 SGChannel *theVideoChannel, SGChannel *theSoundChannel)
  1573. {
  1574.     OSErr     anErr = noErr;
  1575.     long        sgUsage = seqGrabPreview;    // default at least this flag    
  1576.  
  1577.     DebugAssert(s != NULL); if(s == NULL) return badSGChannel;
  1578.  
  1579.     sgUsage |= theUsage;                        // add any other usage flag info now
  1580.  
  1581.     // Create Video Channel.
  1582.     anErr = SGNewChannel(s, VideoMediaType, theVideoChannel); DebugAssert(anErr == noErr);
  1583.     if(anErr != noErr) goto FailureHandling;
  1584.     
  1585.     anErr = SGSetChannelBounds(*theVideoChannel, theBounds); DebugAssert(anErr == noErr);
  1586.     if(anErr != noErr) goto FailureHandling;
  1587.  
  1588.     anErr = SGSetChannelUsage(*theVideoChannel, sgUsage); DebugAssert(anErr == noErr);
  1589.     if(anErr != noErr) goto FailureHandling;
  1590.  
  1591.     // Create Sound Channel.
  1592.     anErr = SGNewChannel(s, SoundMediaType, theSoundChannel); DebugAssert(anErr == noErr);
  1593.     if(anErr != noErr) goto FailureHandling;
  1594.  
  1595.     anErr = SGSetChannelUsage(*theSoundChannel, sgUsage); DebugAssert(anErr == noErr);
  1596.     if(anErr != noErr) goto FailureHandling;
  1597.  
  1598.  
  1599.     return anErr;
  1600.  
  1601. FailureHandling:
  1602.     SGDisposeChannel(s, *theVideoChannel); *theVideoChannel = NULL;
  1603.     SGDisposeChannel(s, *theSoundChannel); *theSoundChannel = NULL;
  1604.  
  1605.     return anErr;
  1606. }
  1607.  
  1608.  
  1609. /*______________________________________________________________________
  1610.     QTUDoesVDIGReceiveVideo - Test if vdig receives a live incoming video signal.
  1611.  
  1612. pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s)
  1613.  
  1614. s                    our sequence grabber component instance
  1615.  
  1616. DESCRIPTION
  1617.     QTUDoesVDIGReceiveVideo test if the currently active vdig is receiving an incoming, live 
  1618.     video signal. We assume that all well behaved vdigs set the digiInSignalLock flag.
  1619.  
  1620. */
  1621. pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s)
  1622. {
  1623.     OSErr        anErr = noErr;
  1624.     long            inputFlags, outFlags;
  1625.  
  1626.     DebugAssert(s != NULL); if(s == NULL) goto Closure;
  1627.  
  1628.     anErr = VDGetCurrentFlags(s, &inputFlags, &outFlags); DebugAssert(anErr == noErr);
  1629.     if(anErr != noErr) goto Closure;
  1630.  
  1631.     if(inputFlags & digiInSignalLock)
  1632.         return true;
  1633.  
  1634. Closure:
  1635.     return false;
  1636. }
  1637.  
  1638.  
  1639. /*______________________________________________________________________
  1640.     QTUChangeSGWindowSize - Change window size of the video sequence grabber window.
  1641.  
  1642. pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, 
  1643.                             WindowPtr theWindow, long width, long height)
  1644.  
  1645. s                    our sequence grabber component instance
  1646. videoChannel    the specified (currently used) video channel
  1647. theWindow    window used for the digitizing sequence
  1648. width            new width of the digitizer rect
  1649. height            new height of the digitizer rect
  1650.  
  1651. DESCRIPTION
  1652.     QTUChangeSGWindowSize shows how to change the window size for the current digitizing sequence
  1653.     taking place in the window. This is more of an example function as there might be other issues
  1654.     to be taken into account (such as preference settings and similar issues) while changing the
  1655.     bounds of the digitizing rect.
  1656.  
  1657. */
  1658.  
  1659. pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, WindowPtr theWindow, long width, long height)
  1660. {
  1661.     OSErr                                 anErr = noErr;
  1662.  
  1663.     DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr;
  1664.     DebugAssert(s != NULL); if(s == NULL) return badSGChannel;
  1665.     DebugAssert(videoChannel != NULL); if(videoChannel == NULL) return badSGChannel;
  1666.  
  1667.     anErr = SGPause(s, TRUE); DebugAssert(anErr == noErr); if(anErr != noErr) goto Closure;
  1668.  
  1669.     SizeWindow(theWindow, width, height, FALSE);
  1670.     
  1671.     anErr = SGSetChannelBounds(videoChannel, &theWindow->portRect); DebugAssert(anErr == noErr);
  1672.     if(anErr != noErr) goto Closure;
  1673.  
  1674.     anErr = SGPause(s, FALSE); DebugAssert(anErr == noErr); 
  1675.  
  1676. Closure:
  1677.     return anErr;
  1678. }
  1679.  
  1680.  
  1681.  
  1682. // COMPONENT FUNCTIONS
  1683.  
  1684. /*______________________________________________________________________
  1685.     QTUDoGetComponent - Get a specific component based on component type and component sub-type.
  1686.  
  1687. pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent)
  1688.  
  1689. theComponentType                    the component type we are interested in
  1690. theSpecificComponent                the specific component sub-type we are interested int
  1691.  
  1692. DESCRIPTION
  1693.     QTUDoGetComponent will get a specific component based on the component type and sub-type.  We have 
  1694.     special code for particular components (for instance movieImporttype and movieExporttype), so
  1695.     if we specify such types, the function will narrow down the search further for the right components.
  1696.     
  1697.     The specificComponent is just the special component we want to search for, if the component type is 
  1698.     NULL, then the Specific component is the one and only we are interested in. Note that we don't care 
  1699.     about the manufacturer information in this function. 
  1700.     
  1701.     If we don't find a suitable component we will return NULL.
  1702. */
  1703.  
  1704. pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent)
  1705. {
  1706.     ComponentDescription     aCD;
  1707.     Component                     aComponent = NULL;
  1708.     
  1709.     aCD.componentType = theComponentType;
  1710.     aCD.componentSubType = theSpecificComponent;
  1711.     aCD.componentManufacturer = 0;
  1712.     
  1713.     // The following code is inserted for special handling of some known cases.
  1714.     if(theComponentType == MovieImportType)
  1715.     {
  1716.         aCD.componentFlags = canMovieImportFiles;
  1717.         aCD.componentFlagsMask = canMovieImportFiles;
  1718.     }
  1719.     else if(theComponentType == MovieExportType)
  1720.     {
  1721.         aCD.componentFlags = canMovieExportFiles;
  1722.         aCD.componentFlagsMask = canMovieExportFiles;
  1723.     }
  1724.  
  1725.     // OK, get the component.
  1726.     aComponent = FindNextComponent((Component)0, &aCD);
  1727.     
  1728.     return aComponent;
  1729. }
  1730.  
  1731.  
  1732. /*______________________________________________________________________
  1733.     QTUHasComponentType -Query for a specific component based on component type and 
  1734.     component sub-type.
  1735.  
  1736. pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent)
  1737.  
  1738. theComponentType                    the component type we are interested in
  1739. theSpecificComponent                the specific component sub-type we are interested int
  1740.  
  1741. DESCRIPTION
  1742.     QTUDoGetComponent will query for a specific component based on the component type and sub-type.  
  1743.     We have special code for particular components (for instance movieImporttype and movieExporttype),
  1744.     so if we query for such types, the function will narrow down the search further for the right 
  1745.     components.
  1746.     
  1747.     The specificComponent is just the special component we want to search for, if the component 
  1748.     type is NULL, then the Specific component is the one and only we are interested in. Note that we 
  1749.     don't care about the manufacturer information in this function. 
  1750.     
  1751.     If we don't find a suitable component we will return false, otherwise we will return true.
  1752. */
  1753.  
  1754. pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent)
  1755. {
  1756.     ComponentDescription aCD;
  1757.     
  1758.     aCD.componentType = theComponentType;
  1759.     aCD.componentSubType = theSpecificComponent;
  1760.     aCD.componentManufacturer = 0;
  1761.     
  1762.     if(theComponentType == MovieImportType)
  1763.     {
  1764.         aCD.componentFlags = canMovieImportFiles;
  1765.         aCD.componentFlagsMask = canMovieImportFiles;
  1766.     }
  1767.     else if(theComponentType == MovieExportType)
  1768.     {
  1769.         aCD.componentFlags = canMovieExportFiles;
  1770.         aCD.componentFlagsMask = canMovieExportFiles;
  1771.     }
  1772.  
  1773.     if(FindNextComponent((Component)0, &aCD) != NULL)
  1774.         return true;
  1775.     else
  1776.         return false;
  1777. }
  1778.  
  1779.  
  1780. //______________________________________________________________________
  1781. // T H E    E N D